package com.erp.order.purchasing.service.impl;

import com.activiti.dao.model.Activiti_SubTaskInfo;
import com.activiti.dao.model.Activiti_SubTaskInfoRO;
import com.activiti.dao.model.Activiti_TaskInfo;
import com.activiti.dao.service.ActivitiService;
import com.activiti.dao.service.TaskSubService;
import com.erp.hr.base.model.ApprovalVO;
import com.erp.hr.base.service.impl.BaseServiceImpl;
import com.erp.hr.base.util.CommonUtils;
import com.erp.hr.base.vo.LegalityResultVO;
import com.erp.hr.base.vo.ResultVO;
import com.erp.hr.dao.model.HrStaff;
import com.erp.hr.dao.model.HrStaffInfoRO;
import com.erp.hr.service.HrStaffDepartmentRService;
import com.erp.order.purchasing.dao.PurchasingAuditDao;
import com.erp.order.purchasing.dao.PurchasingRequisitionDao;
import com.erp.order.purchasing.model.PurchasingAudit;
import com.erp.order.purchasing.model.PurchasingRequisition;
import com.erp.order.purchasing.service.PurchasingAuditService;
import com.erp.order.purchasing.service.PurchasingRequisitionService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.redragon.framework.hibernate.model.Pages;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 采购审核 业务实现层
 * @Author: syz
 * @blame syz
 * @CreateTime: 2021/4/6
 */
@Service
public class PurchasingAuditServiceImpl extends BaseServiceImpl<PurchasingAuditDao, PurchasingAudit> implements PurchasingAuditService {

    /**
     * 采购申请服务
     */
    @Lazy
    @Autowired
    private PurchasingRequisitionService purchasingRequisitionService;

    /**
     * 采购申请dao
     */
    @Lazy
    @Autowired
    private PurchasingRequisitionDao purchasingRequisitionDao;

    /**
     * 流程服务
     */
    @Lazy
    @Autowired
    private ActivitiService activitiService;

    /**
     * 运行时服务
     */
    @Lazy
    @Autowired
    private RuntimeService runtimeService;

    /**
     * 任务服务
     */
    @Lazy
    @Autowired
    private TaskService taskService;

    /**
     * 任务子服务
     */
    @Lazy
    @Autowired
    private TaskSubService taskSubService;

    /**
     * 员工部门服务
     */
    @Lazy
    @Autowired
    private HrStaffDepartmentRService hrStaffDepartmentRService;


    /**
     * 为单个对象添加完整信息
     * @param purchasingAudit 需要添加完整信息的对象
     * @return 添加完整信息后的对象
     */
    @Override
    public PurchasingAudit addCompleteData(PurchasingAudit purchasingAudit) {
        purchasingAudit.setSubs(purchasingRequisitionService.addCompleteData(purchasingRequisitionDao.getListByPurchasingId(purchasingAudit.getId())));
        return purchasingAudit;
    }

    /**
     * 为集合添加完整信息
     * @param list 需要添加完整信息的集合
     * @return 添加完整信息后的集合
     */
    @Override
    public List<PurchasingAudit> addCompleteData(List<PurchasingAudit> list) {
        return list;
    }

    /**
     * 校验数据合法性
     * @param purchasingAudit 需要校验的对象
     * @return 校验结果
     */
    @Override
    public LegalityResultVO isLegalityData(PurchasingAudit purchasingAudit) {
        if (CommonUtils.PURCHASING_AUDIT_TYPE_MONTH.equals(purchasingAudit.getType())) {
            if (!CommonUtils.isApplicationPeriod()) {
                return new LegalityResultVO(true, "不在月采购计划提交期间");
            }
            if (dao.isResubmit(getStaffCodeByDepartment(getStaffInfo().getDepartmentCode()))) {
                return new LegalityResultVO(true, "不可多次提交月采购计划!");
            }
        }
        return new LegalityResultVO(false, null);
    }

    /**
     * 保存对象
     * @param purchasingAudit 需要保存的对象
     * @return 保存结果
     */
    @Override
    public boolean save(PurchasingAudit purchasingAudit) {
        setCode(purchasingAudit);
        HrStaffInfoRO staffInfo = getStaffInfo();
        purchasingAudit.setStatus(CommonUtils.PURCHASING_REQUISITION_STATUS_SUBMIT);
        insertDataObject(purchasingAudit);
        if (purchasingAudit.getSubId() == null) {
            PurchasingRequisition purchasingRequisition = new PurchasingRequisition();
            purchasingRequisition.setIds(purchasingAudit.getSubIds());
            List<PurchasingRequisition> list = purchasingRequisitionService.getDataObjects(purchasingRequisition);
            for (PurchasingRequisition pr : list) {
                pr.setPurchasingId(purchasingAudit.getId());
                pr.setAllowedWithdraw(CommonUtils.IS_DEL_NO);
                setUpdateInfo(pr);
                purchasingRequisitionService.updateDataObject(pr);
            }
        } else {
            PurchasingRequisition pr = purchasingRequisitionService.getDataObject(purchasingAudit.getSubId().toString());
            pr.setPurchasingId(purchasingAudit.getId());
            pr.setAllowedWithdraw(CommonUtils.IS_DEL_NO);
            setUpdateInfo(pr);
            purchasingRequisitionService.updateDataObject(pr);
        }
        String id;
        String key;
        if (CommonUtils.PURCHASING_AUDIT_TYPE_MONTH.equals(purchasingAudit.getType())) {
            id = CommonUtils.MONTH_ACTIVITI_ID;
            key = CommonUtils.MONTH_ACTIVITI_KEY;
        } else {
            id = CommonUtils.SPORADIC_ACTIVITI_ID;
            key = CommonUtils.SPORADIC_ACTIVITI_KEY;
        }
        ProcessInstance processInstance = activitiService.erpStartProcessInstance(
                key,
                "web/approval/toPurchasingApproval?code=" + purchasingAudit.getCode(),
                getActivitiParamMap(purchasingAudit),
                id);
        Task task = activitiService.erpFindPersonalTaskByPid(processInstance.getProcessInstanceId());
        activitiService.erpCompletTask(
                task.getId(),
                isHeadOffice(staffInfo.getCompanyCode()) ? CommonUtils.HEAD_OFFICE : CommonUtils.FILIALE,
                null);
        saveActivitiTaskInfo(
                purchasingAudit.getCode() + "(采购计划签批)",
                staffInfo,
                task,
                processInstance,
                "1");
        saveSubActivitiTaskInfo(
                staffInfo,
                task,
                processInstance,
                "1",
                "1",
                staffInfo.getStaffName() + "发起采购计划签批");
        purchasingAudit.setProcessInstanceId(processInstance.getProcessInstanceId());
        updateDataObject(purchasingAudit);
        return true;
    }

    /**
     * 获取流程参数map
     * @param purchasingAudit 采购计划对象
     * @return 流程参数map
     */
    private Map<String, Object> getActivitiParamMap(PurchasingAudit purchasingAudit) {
        Long id = purchasingAudit.getId();
        Map<String, Object> result = new HashMap<>(9);
        HrStaffInfoRO staffInfo = getStaffInfo();
        if (isHeadOffice(staffInfo.getCompanyCode())) {
            result.put("flzg_id", staffInfo.getStaffCode());
            result.put("sqbmfzr_id_list", getCodeSetByDepartmentCode(getRequisitionDepartmentCodes(id), CommonUtils.BMFZR));
            result.put("sqbmfgld_id_list", getCodeSetByDepartmentCode(getRequisitionDepartmentCodes(id), CommonUtils.FGLD));
            result.put("ywglbmfzr_id_list", getCodeSetByDepartmentCode(
                    new HashSet<String>() {{
                        add(CommonUtils.VIRTUAL_DEPARTMENT_CODE);
                    }},
                    CommonUtils.BMFZR));
            result.put("ywzg_id_list", getCodeSetByDepartmentCode(
                    new HashSet<String>() {{
                        add(CommonUtils.VIRTUAL_DEPARTMENT_CODE);
                    }},
                    CommonUtils.CGZZ));
        } else {
            result.put("flzg_id", staffInfo.getStaffCode());
            result.put("xmfzr_id_list", getCodeSetByDepartmentCode(getRequisitionDepartmentCodes(id), CommonUtils.XMFZR));
            result.put("fgsfzr_id_list", getCodeSetByCompanyCode(getRequisitionCompanyCodes(id), CommonUtils.FGSFZR));
            result.put("ywzg_id_list", getCodeSetByCompanyCode(getRequisitionCompanyCodes(id), CommonUtils.CGZZ));
        }
        if (CommonUtils.PURCHASING_AUDIT_TYPE_MONTH.equals(purchasingAudit.getType())) {
            if (isHeadOffice(staffInfo.getCompanyCode())) {
                result.put("jhwzzgy_id_list", getCodeSetByCompanyCode(CommonUtils.JHWZZGY));
                result.put("jyjhzg_id_list", getCodeSetByCompanyCode(CommonUtils.JYJHBWZZG));
                result.put("jyjhfzr_id_list", getCodeSetByCompanyCode(CommonUtils.JYJHBFZR));
                result.put("fgld_id_list", getCodeSetByCompanyCode(CommonUtils.GSJYFGLD));
            } else {
                result.put("jhwzzgy_id_list", getCodeSetByCompanyCode(getRequisitionCompanyCodes(id), CommonUtils.JHWZZGY));
                result.put("jyjhzg_id_list", getCodeSetByCompanyCode(getRequisitionCompanyCodes(id), CommonUtils.JYJHBWZZG));
                result.put("jyjhfzr_id_list", getCodeSetByCompanyCode(getRequisitionCompanyCodes(id), CommonUtils.JYJHBFZR));
                result.put("fgld_id_list", getCodeSetByCompanyCode(getRequisitionCompanyCodes(id), CommonUtils.GSJYFGLD));
            }
        }
        return result;
    }

    /**
     * 获取申请公司编码集合
     * @param id 采购计划id
     * @return 申请公司编码集合
     */
    private Set<String> getRequisitionCompanyCodes(Long id) {
        List<PurchasingRequisition> list = purchasingRequisitionDao.getListByPurchasingId(id);
        Set<String> codes = new HashSet<>();
        for (PurchasingRequisition pr : list) {
            codes.add(pr.getCompanyCode());
        }
        return codes;
    }

    /**
     * 获取申请部门编码集合
     * @param id 采购计划id
     * @return 申请部门编码集合
     */
    private Set<String> getRequisitionDepartmentCodes(Long id) {
        List<PurchasingRequisition> list = purchasingRequisitionDao.getListByPurchasingId(id);
        Set<String> codes = new HashSet<>();
        for (PurchasingRequisition pr : list) {
            codes.add(pr.getDepartmentCode());
        }
        return codes;
    }

    /**
     * 保存流程任务信息
     * @param bussname 任务名称
     * @param staffInfo 操作人信息
     * @param task 任务信息
     * @param processInstance 进程实例
     * @param status 状态
     */
    private void saveActivitiTaskInfo(String bussname, HrStaffInfoRO staffInfo, Task task, ProcessInstance processInstance, String status) {
        Activiti_TaskInfo activitiTaskInfo = new Activiti_TaskInfo();
        activitiTaskInfo.setCompany_code(staffInfo.getCompanyCode());
        activitiTaskInfo.setTask_id(Integer.parseInt(task.getId()));
        activitiTaskInfo.setDepartment_code(staffInfo.getDepartmentCode());
        activitiTaskInfo.setProc_name(bussname);
        activitiTaskInfo.setProc_inst_id(processInstance.getProcessInstanceId());
        activitiTaskInfo.setStaff_code(staffInfo.getStaffCode());
        activitiTaskInfo.setStatus(status);
        activitiTaskInfo.setCreate_time(new Date());
        activitiService.insertOrUpdateDataObject(activitiTaskInfo);
    }

    /**
     * 保存流程任务详情信息
     * @param staffInfo 操作人信息
     * @param task 任务信息
     * @param processInstance 进程实例
     * @param status 状态
     * @param subStatus 详情状态
     * @param subcontent 内容
     */
    private void saveSubActivitiTaskInfo(HrStaffInfoRO staffInfo, Task task, ProcessInstance processInstance, String status, String subStatus, String subcontent) {
        Activiti_TaskInfo activitiTaskInfo = activitiService.queryActivitiTaskInfoByPid(processInstance.getProcessInstanceId());
        activitiTaskInfo.setStatus(status);
        activitiService.updateDataObject(activitiTaskInfo);
        Activiti_SubTaskInfo activitiSubTaskInfo = new Activiti_SubTaskInfo();
        activitiSubTaskInfo.setTask_id(Integer.parseInt(processInstance.getProcessInstanceId()));
        activitiSubTaskInfo.setCompany_code(staffInfo.getCompanyCode());
        activitiSubTaskInfo.setCreate_time(new Date());
        activitiSubTaskInfo.setTask_sub_id(Integer.parseInt(task.getId()));
        activitiSubTaskInfo.setTask_sub_name(task.getName());
        activitiSubTaskInfo.setDepartment_code(staffInfo.getDepartmentCode());
        activitiSubTaskInfo.setStatus(subStatus);
        activitiSubTaskInfo.setProc_contents(subcontent);
        activitiSubTaskInfo.setStaff_code(staffInfo.getStaffCode());
        activitiSubTaskInfo.setProc_time(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        taskSubService.insertOrUpdateDataObject(activitiSubTaskInfo);
    }

    /**
     * 设置计划编号
     * @param purchasingAudit 需要设置计划编号的对象
     */
    private void setCode(PurchasingAudit purchasingAudit) {
        StringBuilder sb = new StringBuilder();
        if (CommonUtils.PURCHASING_AUDIT_TYPE_SPORADIC.equals(purchasingAudit.getType())) {
            sb.append(CommonUtils.PREFIX_SPORADIC);
        } else {
            sb.append(CommonUtils.PREFIX_MONTH);
        }
        Calendar calendar = Calendar.getInstance();
        sb.append(calendar.get(Calendar.YEAR));
        sb.append(calendar.get(Calendar.MONTH) + 1);
        sb.append(calendar.get(Calendar.DATE));
        sb.append(getCodeSuffix(purchasingAudit.getType()));
        purchasingAudit.setCode(sb.toString());
    }

    /**
     * 获取申请编号后缀
     * @param type 申请类型
     * @return 申请编号后缀
     */
    private String getCodeSuffix(String type) {
        Integer num = dao.getRequisitionCount(type) + 1;
        String suffix = num.toString();
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < CommonUtils.PURCHASING_REQUISITION_LENGRH - suffix.length(); i ++) {
            result.append("0");
        }
        result.append(suffix);
        return result.toString();
    }

    /**
     * 更新对象
     * @param purchasingAudit 需要更新的对象
     * @return 更新结果
     */
    @Override
    public boolean update(PurchasingAudit purchasingAudit) {
        return false;
    }

    /**
     * 根据id删除对象及相关信息
     * @param id 需要删除对象的id
     * @return 删除结果
     */
    @Override
    public boolean linkDelete(Long id) {
        return false;
    }

    /**
     * 获取任务信息
     * @param processInstanceId 流程实例id
     * @return 任务信息集合
     */
    @Override
    public List<Activiti_SubTaskInfoRO> getTaskInfo(String processInstanceId) {
        return taskSubService.getDataObjects(processInstanceId);
    }

    /**
     * 是否指定下一人
     * @param processInstanceId 流程实例id
     * @return 是否指定下一人
     */
    @Override
    public boolean isAssignNext(String processInstanceId) {
        String key = activitiService.erpGetCurrentTask(processInstanceId,getStaffInfo().getStaffCode()).getTaskDefinitionKey();
        return CommonUtils.SPORADIC_ACTIVITI_3.equals(key) || CommonUtils.MONTH_ACTIVITI_3.equals(key);
    }

    /**
     * 获取可合并列表分页数据
     * @param s 不知道干啥用的
     * @param pages 分页对象
     * @param purchasingRequisition 采购申请对象
     * @return 可合并列表分页数据
     */
    @Override
    public List<PurchasingRequisition> getSubPageList(String s, Pages pages, PurchasingRequisition purchasingRequisition) {
        return purchasingRequisitionService.addCompleteData(dao.getSubPageList("", pages, purchasingRequisition));
    }

    /**
     * 获取申请对象
     * @param id 申请id
     * @return 申请对象
     */
    @Override
    public PurchasingRequisition getSub(String id) {
        return purchasingRequisitionService.addCompleteData(
                purchasingRequisitionService.getDataObject(id));
    }

    /**
     * 执行审批
     * @param approvalVO 审批vo对象
     * @return 审批结果
     */
    @Override
    public ResultVO<String> approval(ApprovalVO approvalVO) {
        String status;
        PurchasingAudit pa = dao.getDataObject(approvalVO.getDataCode());
        if (StringUtils.isNotEmpty(approvalVO.getNext())) {
            pa.setBuyer(approvalVO.getNext());
            setUpdateInfo(pa);
            updateDataObject(pa);
        }
        Task task = taskService.createTaskQuery().taskId(approvalVO.getTaskId()).singleResult();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(approvalVO.getProcessInstanceId()).singleResult();
        activitiService.erpCompletTask(approvalVO.getTaskId(), approvalVO.getResult(),null);
        if(runtimeService.createProcessInstanceQuery().processInstanceId(approvalVO.getProcessInstanceId()).singleResult() == null) {
            String resultStatus = CommonUtils.PASS.equals(approvalVO.getResult())
                    ? CommonUtils.PURCHASING_REQUISITION_STATUS_AUDIT_END
                    : CommonUtils.PURCHASING_REQUISITION_STATUS_REJECT;
            pa.setStatus(resultStatus);
            setUpdateInfo(pa);
            updateDataObject(pa);
            List<PurchasingRequisition> subs = purchasingRequisitionDao.getListByPurchasingId(pa.getId());
            for (PurchasingRequisition pr : subs) {
                pr.setStatus(resultStatus);
                setUpdateInfo(pr);
                purchasingRequisitionService.updateDataObject(pr);
            }
            status = CommonUtils.APPROVAL_STATUS_END;
        } else {
            if(CommonUtils.REJECT.equals(approvalVO.getResult())){
                status = CommonUtils.APPROVAL_STATUS_REJECT;
                pa.setStatus(CommonUtils.PURCHASING_REQUISITION_STATUS_REJECT);
                setUpdateInfo(pa);
                updateDataObject(pa);
                List<PurchasingRequisition> subs = purchasingRequisitionDao.getListByPurchasingId(pa.getId());
                for (PurchasingRequisition pr : subs) {
                    pr.setStatus(CommonUtils.PURCHASING_REQUISITION_STATUS_REJECT);
                    setUpdateInfo(pr);
                    purchasingRequisitionService.updateDataObject(pr);
                }
            }else{
                status = CommonUtils.APPROVAL_STATUS_UNDERWAY;
            }
        }
        saveSubActivitiTaskInfo(getStaffInfo(), task, processInstance, status, approvalVO.getResult(), approvalVO.getContent());
        return ResultVO.success();
    }

    /**
     * 获取采购员集合
     * @param code 采购计划编码
     * @return 采购员集合
     */
    @Override
    public List<HrStaff> getBuyer(String code) {
        if (isHeadOffice(getStaffInfo().getCompanyCode())) {
            return hrStaffDepartmentRService.getAllStaffByPostCode(CommonUtils.CGY);
        } else {
            List<HrStaff> result = new ArrayList<>();
            for (String s : getRequisitionCompanyCodes(getDataObject(code).getId())) {
                result.addAll(hrStaffDepartmentRService.getAllStaffByPostCode(s, CommonUtils.CGY));
            }
            return result;
        }
    }

}